import os
from utils.common import dynamicImport
import re
import json
import types

def instance_variable_name_of_class(classname):
    if ord(classname[0])>=65 and ord(classname[0])<91:
        return classname[0].upper()+classname[1:]
    else:
        return '_'+classname

def build_model(model,dataset,preprocessor,filename,type):
    '''
    生成训练模型的代码

    Args:
        model: 模型字典
        dataset: 数据集字典
        preprocessor: 预处理器字典
        filename: 生成的python文件路径
        type: 测试类型
    '''
    with open(filename, 'w', encoding='utf8') as f:
        contents='''
import sys
import os

from procedures import train_procedure

sys.path.append(%s)

from %s import %s

model_init_d=%s
%s=%s(**model_init_d)
train_procedure(%s,%s)
'''%(os.path.basename(model['file'])[:-3],model['class'],os.path.dirname(model['file']),model['parameters'],instance_variable_name_of_class(model['class']),model['class'],instance_variable_name_of_class(model['class']),dataset['path'])
        f.write(contents)

def getInputAndOutputLayers(model): # param:model:tf.keras.models.Model; return list of layers
    inputLayerNames=[]
    outputLayerNames=[]
    inputLayers=[]
    outputLayers=[]
    for layer in sm251bn.model.layers:
        if not isinstance(layer.input,list) and not isinstance(layer.output,list) and layer.input.name==layer.output.name:
            inputLayerNames.append(layer.input.name)
        ins=set()
        outs=set()
        if not isinstance(layer.input,list):
            ins.add(layer.input.name.split('/')[0])
        else:
            for li in layer.input:
                ins.add(li.name.split('/')[0])
        if not isinstance(layer.output,list):
            outs.add(layer.output.name.split('/')[0])
        else:
            for lo in layer.output:
                outs.add(lo.name.split('/')[0])
    for o in outs:
        if o not in ins:
            outputLayerNames.append(o)

    for layer in sm251bn.model.layeers:
        if layer.name in inputLayerNames:
            inputLayers.append(layer)
        if layer.name in outputLayerNames:
            outputLayers.append(layer)
    return inputLayers,outputLayers

def askSourceCode():
    classname=input('classname\n')
    attribute=input('attribute\n')
    parameters=input('parameters\n')
    return classname,attribute,parameters

def getStrOriValue(st):
    if st.startswith('('):
        return parseParams(st[1:-1])[0]
    elif st.startswith('['):
        return list(parseParams(st[1:-1])[0])
    elif st.startswith('{'):
        return json.loads(st)  # 测试人员写字典字符串时，如果想表达True的概念，要写成true,因为json中true的写法是小写t,据此json识别出true并转成python中True,False同理
    elif st.startswith('"') or st.startswith('\''):
        return str(st)
    elif st=='True':
        return True
    elif st=='False':
        return False
    elif re.match(r'^[\+\-]?\d+$',st):
        return int(st)
    elif re.match(r'^[\+\-]?\d+(\.\d+)?e[\+\-]?\d+([\+\-]{1}\d+)*$',st) or re.match(r'^[\+\-]?\d+\.\d+$',st):
        return float(st)
    else:
        return str(st)

def str2oriValue(st,t,d):
    searchResult=re.search(r'^(\w+)=(.+)',st)
    if searchResult is None:
        t.append(getStrOriValue(st))
    else:
        d[searchResult.group(1)]=getStrOriValue(searchResult.group(2))

def parseParams(parameters):
    t=[]
    d={}
    orii=i=0
    oneParamFlag=0
    doubleQuoteFlag=False
    uniqueQuoteFlag=False
    parameters=''.join(parameters.split())
    while i<len(parameters):
        if not oneParamFlag and not doubleQuoteFlag and not uniqueQuoteFlag and parameters[i]==',':
            str2oriValue(parameters[orii:i],t,d)
            orii=i+1
        if parameters[i] in ('(','[','{'):
            oneParamFlag+=1
        elif parameters[i] in (')',']','}'):
            oneParamFlag-=1
        elif parameters[i]=='"':
            doubleQuoteFlag=not doubleQuoteFlag
        elif parameters[i]=='\'':
            uniqueQuoteFlag=not uniqueQuoteFlag
        i+=1
    if orii!=len(parameters):
        str2oriValue(parameters[orii:],t,d)
    return tuple(t),d

def isLoadableModelSource(model):
    if isinstance(model,object):
        return True
    else:
        return False

def gen_model_conf(name,typ,filePath):
    if filePath.endswith('.py'):
        if os.path.exists(f'models/{name}.py'): # TODO: delete
            os.remove(f'models/{name}.py')
        if f'{name}.py' in os.listdir('models'):
            return 1,'Used model name,please change one'
        with open(f'models/{name}.py','w',encoding='utf8') as f:
            with open(filePath,encoding='utf8') as fr:
                f.write(fr.read())
        # classname,attribute,parameters=askSourceCode()
        classname='SpeechModel251BN'
        attribute='model'
        parameters='(1600,200,1),1429'
        obj=dynamicImport(f'models.{name}:{classname}')
        t,d=parseParams(parameters)
        if isinstance(model,types.FunctionType):
            res=obj(*t,**d) # obj是函数，则模型只能是返回值构建来的

        ins=obj(*t,**d)
        print(ins.__dict__)
        model=getattr(ins,attribute)
        if isinstance(model,object):
            print('instance get success')
        elif isinstance(model,types.FunctionType):
            pass # 大概率是函数的返回值，还要请求函数的参数
        else:
            return 1,'unable to load the model'
    else:
        pass

if __name__=='__main__':
    file='models/keras_backend.py'
    gen_model_conf('SpeechRecognition251BN','DL',file)
    # parseParams('(1600,200,1),1429')